package com.hyt.it.ogt.ykcj.service.exam.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hyt.core.base.BaseEntity;
import com.hyt.core.constant.CommonConstant;
import com.hyt.it.ogt.common.config.RedisKeyConstant;
import com.hyt.it.ogt.ykcj.common.core.domain.entity.SysDictData;
import com.hyt.it.ogt.ykcj.common.enums.CommonEnums;
import com.hyt.it.ogt.ykcj.common.enums.ExamFormEnums;
import com.hyt.it.ogt.ykcj.common.enums.ExamTypeEnums;
import com.hyt.it.ogt.ykcj.common.enums.zs.CertificatePublishTypeEnums;
import com.hyt.it.ogt.ykcj.common.exception.CustomException;
import com.hyt.it.ogt.ykcj.common.utils.DateUtils;
import com.hyt.it.ogt.ykcj.common.utils.IdUtils;
import com.hyt.it.ogt.ykcj.common.utils.SecurityUtils;
import com.hyt.it.ogt.ykcj.common.utils.bean.BeanUtils;
import com.hyt.it.ogt.ykcj.domain.exam.*;
import com.hyt.it.ogt.ykcj.domain.grade.EnterpriseExamineeInfo;
import com.hyt.it.ogt.ykcj.domain.grade.EnterpriseExamineeSubjectGrade;
import com.hyt.it.ogt.ykcj.domain.param.*;
import com.hyt.it.ogt.ykcj.domain.vo.*;
import com.hyt.it.ogt.ykcj.domain.zs.ZsInfo;
import com.hyt.it.ogt.ykcj.domain.zs.vo.ZsInfoVO;
import com.hyt.it.ogt.ykcj.feign.model.Classification;
import com.hyt.it.ogt.ykcj.mapper.exam.*;
import com.hyt.it.ogt.ykcj.mapper.grade.EnterpriseExamineeInfoMapper;
import com.hyt.it.ogt.ykcj.mapper.grade.EnterpriseExamineeSubjectGradeMapper;
import com.hyt.it.ogt.ykcj.service.exam.IClassificationService;
import com.hyt.it.ogt.ykcj.service.exam.IEnterpriseExamScoreLineSettingService;
import com.hyt.it.ogt.ykcj.service.exam.IExamInfoService;
import com.hyt.it.ogt.ykcj.service.exam.IExamSubjectInfoService;
import com.hyt.it.ogt.ykcj.service.grade.IEnterpriseExamineeInfoService;
import com.hyt.it.ogt.ykcj.service.grade.IEnterpriseExamineeSubjectGradeService;
import com.hyt.it.ogt.ykcj.service.grade.IEnterpriseGroupExamineeInfoService;
import com.hyt.it.ogt.ykcj.service.zs.IZsInfoService;
import com.hyt.loginfo.service.IBaseLoginService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 考试信息Service业务层处理
 *
 * @author admin
 * @date 2021-06-18
 */
@Service
public class ExamInfoServiceImpl implements IExamInfoService {
    @Autowired
    private ExamInfoMapper examInfoMapper;

    @Autowired
    private ExamSubjectInfoMapper examSubjectInfoMapper;

    @Autowired
    private ExamStemInfoMapper examStemInfoMapper;

    @Autowired
    private ExamNameConfigMapper examNameConfigMapper;

    @Autowired
    private ExamSubjectNameConfigMapper examSubjectNameConfigMapper;

    @Autowired
    private EnterpriseExamineeSubjectGradeMapper enterpriseExamineeSubjectGradeMapper;

    @Autowired
    private IBaseLoginService iBaseLoginService;

    @Autowired
    private IEnterpriseExamScoreLineSettingService iEnterpriseExamScoreLineSettingService;

    @Autowired
    private IEnterpriseExamineeSubjectGradeService iEnterpriseExamineeSubjectGradeService;

    @Autowired
    private EnterpriseExamineeInfoMapper enterpriseExamineeInfoMapper;

    @Autowired
    private IEnterpriseExamineeInfoService enterpriseExamineeInfoService;

    @Autowired
    private IExamSubjectInfoService iExamSubjectInfoService;

    @Resource(name = "threadPoolTaskExecutor")
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private EnterpriseExamScoreLineSettingSubMapper enterpriseExamScoreLineSettingSubMapper;

    @Autowired
    private IClassificationService classificationService;

    @Autowired
    private IEnterpriseGroupExamineeInfoService enterpriseGroupExamineeInfoService;

    @Autowired
    private IZsInfoService zsInfoService;

    /**
     * 查询考试信息
     *
     * @param id 考试信息ID
     * @return 考试信息
     */
    @Override
    public ExamInfoVo selectExamInfoById(String id) throws Exception {
        Map<String, Object> parms = new HashedMap<>();
        parms.put("id", id);
        List<ExamInfoVo> examInfoVos = examInfoMapper.selectExamInfoByParms(parms);
        if (CollectionUtils.isEmpty(examInfoVos)) {
//    		throw new Exception(BizErrorCode.EXAM_E0005.getErrMsg());
            return new ExamInfoVo();
        }
        ExamInfoVo examInfoVo = examInfoVos.get(0);
        ExamSubjectInfo info = new ExamSubjectInfo();
        info.setExamInfoId(examInfoVo.getId());
        List<ExamSubjectInfo> subInfos = examSubjectInfoMapper.selectExamSubjectInfoList(info);
        if ("1".equals(examInfoVo.getExamType())) {
            List<ExamSubjectVo> subVos = new ArrayList<ExamSubjectVo>();
            for (ExamSubjectInfo subInfo : subInfos) {
                ExamSubjectVo subVo = new ExamSubjectVo();
                BeanUtils.copyBeanProp(subVo, subInfo);
                ExamStemInfo examStemInfo = new ExamStemInfo();
                examStemInfo.setSubjectId(subInfo.getId());
                subVo.setExamStemInfo(examStemInfoMapper.selectExamStemInfoList(examStemInfo));
                subVos.add(subVo);
            }
            examInfoVo.setSubjectVos(subVos);
        } else {
            examInfoVo.setSubjectInfo(subInfos);
        }
        return examInfoVo;
    }

    /**
     * 查询考试信息列表
     *
     * @param examInfo 考试信息
     * @return
     */
    @Override
    public List<ExamInfo> selectExamInfoList(ExamInfo examInfo) {
        return examInfoMapper.selectExamInfoList(examInfo);
    }

    /**
     * 根据考试名称Id查询最近一次考试信息并返回
     *
     * @param @param  examNameConfigId
     * @param @return
     */
    @Override
    public ExamInfoVo selectExamInfoByExamNameId(String examNameConfigId, String year) throws Exception {
        Map<String, Object> parms = new HashedMap<>();
        parms.put("examNameConfigId", examNameConfigId);
        parms.put("year", year);
        List<ExamInfoVo> examInfoVos = examInfoMapper.selectExamInfoByParms(parms);
        if (CollectionUtils.isEmpty(examInfoVos)) {
            return new ExamInfoVo();
        }
        ExamSubjectInfo info = new ExamSubjectInfo();
        info.setExamInfoId(examInfoVos.get(0).getId());
        List<ExamSubjectInfo> subInfos = examSubjectInfoMapper.selectExamSubjectInfoList(info);

        examInfoVos.get(0).setSubjectInfo(subInfos);
        return examInfoVos.get(0);
    }

    /**
     * 获取考试分类
     *
     * @param examNameConfigId 考试名称ID
     * @return
     */
    @Override
    public List<SysDictData> getExamType(String examNameConfigId) {
        return examInfoMapper.getExamType(examNameConfigId);
    }

    /**
     * 查询考试ID
     *
     * @param examNameConfigId 考试名称ID
     * @param civilServantType 公务员考试类别
     * @param year             考试年份
     * @return
     */
    @Override
    public String getExamId(String examNameConfigId, String civilServantType, String year) {
        ExamInfo examInfo = new ExamInfo();
        examInfo.setExamNameConfigId(examNameConfigId);
        examInfo.setCivilServantType(civilServantType);
        examInfo.setYear(year);
        List<ExamInfo> list = examInfoMapper.selectExamInfoList(examInfo);
        if (CollectionUtils.isNotEmpty(list)) {
            examInfo = list.get(0);
        }
        return examInfo.getId();
    }

    @Override
    public List<EnterpriseExamVo> pageEnterpriseExamInfoSelectList(ExamPageParam examPageParam) {
        List<EnterpriseExamVo> result = new ArrayList<>();
        Map<String, Object> queryMap = new HashMap<>();
        List<Classification> classificationList = new ArrayList<>();
        if (!"all".equals(examPageParam.getExamType())) {
            classificationList = classificationService.getChildList(examPageParam.getExamType());
        }
        String[] examTypes = ArrayUtil.removeEmpty(classificationList.stream().map(item -> item.getId()).toArray(String[]::new));

        // 分页查询
        Integer pageNo = examPageParam.getPageNum();
        Integer pageSize = examPageParam.getPageSize();
        PageInfo<ExamInfoVo> pageInfo = PageHelper.startPage(pageNo, pageSize).doSelectPageInfo(() -> {
            if (ArrayUtil.isNotEmpty(examTypes)) {
                queryMap.put("examTypes", examTypes);
            }
            queryMap.put("examNameConfigName", examPageParam.getExamName());
            queryMap.put("officeId", iBaseLoginService.getOfficeId());
            queryMap.put("examForm", String.valueOf(ExamFormEnums.FORM_EXAM.getCode()));
            queryMap.put("examGroupId", examPageParam.getExamGroupId());
            examInfoMapper.examInfoSelectList(queryMap);
        });
        List<ExamInfoVo> examInfos = pageInfo.getList();
        long total = new PageInfo(examInfos).getTotal();
        examPageParam.setTotal(total);

        // 考试分类
        List<Classification> classificationTree = classificationService.getClassificationList();
        if (CollectionUtil.isNotEmpty(examInfos)) {
            String[] ids = examInfos.stream().map(ExamInfoVo::getId).toArray(String[]::new);
            List<ExamSubjectVo> subjectList = examSubjectInfoMapper.selectExamSubjectInfoByExamIds(ids);
            Map<String, List<ExamSubjectVo>> subjectMap = subjectList.stream().collect(Collectors.groupingBy(ExamSubjectVo::getExamInfoId));

            for (ExamInfoVo examInfo : examInfos) {
                EnterpriseExamVo enterpriseExamVoResult = buildExamInfoData(examInfo, subjectMap, classificationTree);
                result.add(enterpriseExamVoResult);
            }
        }
        return result;
    }


    @Override
    public List<EnterpriseExamVo> pageEnterpriseExamInfoList(ExamPageParam examPageParam) {
        List<EnterpriseExamVo> result = new ArrayList<>();
        Map<String, Object> queryMap = new HashMap<>();
        List<Classification> classificationList = new ArrayList<>();
        if (!"all".equals(examPageParam.getExamType())) {
            classificationList = classificationService.getChildList(examPageParam.getExamType());
        }
        String[] examTypes = ArrayUtil.removeEmpty(classificationList.stream().map(item -> item.getId()).toArray(String[]::new));

        // 分页查询
        Integer pageNo = examPageParam.getPageNum();
        Integer pageSize = examPageParam.getPageSize();
        PageInfo<ExamInfoVo> pageInfo = PageHelper.startPage(pageNo, pageSize).doSelectPageInfo(() -> {
            if (ArrayUtil.isNotEmpty(examTypes)) {
                queryMap.put("examTypes", examTypes);
            }
            queryMap.put("examNameConfigName", examPageParam.getExamName());
            queryMap.put("year", examPageParam.getYear());
            queryMap.put("examStartDay", examPageParam.getExamStartDay());
            queryMap.put("examEndDay", examPageParam.getExamEndDay());
            queryMap.put("officeId", iBaseLoginService.getOfficeId());
            queryMap.put("deptIds", examPageParam.getDeptIds());
            queryMap.put("examForm", examPageParam.getExamForm());
            examInfoMapper.selectEnterpriseExamInfoByParms(queryMap);
        });
        List<ExamInfoVo> examInfos = pageInfo.getList();

        if (CollectionUtils.isEmpty(examInfos)) {
            return result;
        }
        long total = new PageInfo(examInfos).getTotal();
        examPageParam.setTotal(total);

        // 获取科目数据
        String[] ids = examInfos.stream().map(ExamInfoVo::getId).toArray(String[]::new);
        // 子考试的科目id搞里头
        for (ExamInfoVo examInfoVo : examInfos) {
            if (ExamFormEnums.FORM_EXAM_GROUP.getCode().equals(examInfoVo.getExamForm())) {
                queryMap.clear();
                queryMap.put("relationId", examInfoVo.getId());
                List<ExamInfoVo> examInfosSub = examInfoMapper.selectEnterpriseExamInfoByParms(queryMap);
                String[] idsSub = examInfosSub.stream().map(ExamInfoVo::getId).toArray(String[]::new);
                if (idsSub.length > 0) {
                    ids = ArrayUtil.addAll(ids, idsSub);
                }
                examInfoVo.setChildren(examInfosSub);
            }
        }
        List<ExamSubjectVo> subjectList = examSubjectInfoMapper.selectExamSubjectInfoByExamIds(ids);
        // 赋值这个科目是不是合并科目
        List<ExamSubjectInfo> subjectRelList = iExamSubjectInfoService.lambdaQuery().isNotNull(ExamSubjectInfo::getRelationId).list();
        if (CollectionUtil.isNotEmpty(subjectRelList)) {
            List<String> relationIdList = subjectRelList.stream().map(item -> item.getRelationId()).distinct().collect(Collectors.toList());
            subjectList.stream().forEach(item -> {
                if (relationIdList.contains(item.getSubjectId())) {
                    item.setType(true);
                } else {
                    item.setType(false);
                }
            });
        }

        Map<String, List<ExamSubjectVo>> subjectMap = subjectList.stream().collect(Collectors.groupingBy(ExamSubjectVo::getExamInfoId));
        List<Classification> classificationTree = classificationService.getClassificationList();
        // 封装数据，包括子考试
        for (ExamInfoVo examInfo : examInfos) {
            EnterpriseExamVo enterpriseExamVoResult = buildExamInfoData(examInfo, subjectMap, classificationTree);
            if (CollectionUtils.isNotEmpty(examInfo.getChildren())) {
                List<EnterpriseExamVo> childrenResult = new ArrayList<>();
                List<ExamInfoVo> children = examInfo.getChildren();
                for (ExamInfoVo examInfoSub : children) {
                    EnterpriseExamVo enterpriseExamVoChildResult = buildExamInfoData(examInfoSub, subjectMap, classificationTree);
                    childrenResult.add(enterpriseExamVoChildResult);
                }
                enterpriseExamVoResult.setExamChildren(childrenResult);
            }
            result.add(enterpriseExamVoResult);
        }

        // 考试组归档状态
        if (String.valueOf(ExamFormEnums.FORM_EXAM_GROUP.getCode()).equals(examPageParam.getExamForm())) {
            setArchivedStatus(result);
        }

        return result;
    }

    /**
     * 设置考试组归档状态
     *
     * @param examInfos
     */
    private void setArchivedStatus(List<EnterpriseExamVo> examInfos) {
        List<String> ids = examInfos.stream().map(item -> item.getExamId()).collect(Collectors.toList());
        Map<String, List<ExamInfo>> groupMap = new HashedMap<>();

        for (EnterpriseExamVo item : examInfos) {
            if (CommonEnums.EXAM_MERGE_TYPE_0.getCode().equals(item.getMergeType())) {
                ExamInfo query = new ExamInfo();
                query.setRelationId(item.getExamId());
                List<ExamInfo> examInfos1 = examInfoMapper.selectExamInfoList(query);
                ids.addAll(examInfos1.stream().map(item1 -> item1.getId()).collect(Collectors.toSet()));
                groupMap.put(item.getExamId(), examInfos1);
            }
        }

        List<EnterpriseExamineeInfo> enterpriseExamineeInfos = enterpriseExamineeInfoMapper.selectEnterpriseExamineeInfoByExamIds(ids);
        if (CollectionUtils.isNotEmpty(enterpriseExamineeInfos)) {
            Map<String, List<EnterpriseExamineeInfo>> collect = enterpriseExamineeInfos.stream()
                    .filter(item -> CommonEnums.ARCHIVED_STATUS_Y.getCode().equals(item.getArchivedStatus())).collect(Collectors.groupingBy(item -> item.getExamId()));
            Map<String, List<EnterpriseExamineeInfo>> collectGroup = enterpriseExamineeInfos.stream()
                    .filter(item -> CommonEnums.ARCHIVED_STATUS_Y.getCode().equals(item.getArchivedGroupStatus())).collect(Collectors.groupingBy(item -> item.getExamId()));

            for (EnterpriseExamVo item : examInfos) {
                if (CommonEnums.EXAM_MERGE_TYPE_0.getCode().equals(String.valueOf(item.getMergeType()))) {
                    List<ExamInfo> examInfos1 = groupMap.get(item.getExamId());
                    int flag = 0;
                    for (ExamInfo item1 : examInfos1) {
                        if (CollectionUtils.isNotEmpty(collectGroup.get(item1.getId()))) {
                            flag += 1;
                        }
                    }
                    if (flag > 0) {
                        item.setArchivedStatus(true);
                    } else {
                        item.setArchivedStatus(false);
                    }
                } else {
                    if (CollectionUtils.isNotEmpty(collect.get(item.getExamId()))) {
                        item.setArchivedStatus(true);
                    } else {
                        item.setArchivedStatus(false);
                    }
                }
            }
        }
    }

    /**
     * 组装考试返回数据
     *
     * @param examInfo
     * @param subjectMap
     */
    private EnterpriseExamVo buildExamInfoData(ExamInfoVo examInfo, Map<String, List<ExamSubjectVo>> subjectMap, List<Classification> classificationTree) {
        EnterpriseExamVo enterpriseExamVo = new EnterpriseExamVo();
        enterpriseExamVo.setExamId(examInfo.getId());
        enterpriseExamVo.setExamName(examInfo.getExamNameConfigName());
        if (examInfo.getExamStartDay() != null && examInfo.getExamEndDay() != null) {
            enterpriseExamVo.setExamTime(StringUtils.join(DateUtil.format(examInfo.getExamStartDay(), "MM-dd HH:mm"),
                    "~", DateUtil.format(examInfo.getExamEndDay(), "MM-dd HH:mm")));
        }
        if (examInfo.getUpdateTime() != null) {
            enterpriseExamVo.setUpdateTime(DateUtil.formatDateTime(examInfo.getUpdateTime()));
        }
        enterpriseExamVo.setYear(examInfo.getYear());
        enterpriseExamVo.setOrigin(examInfo.getOrigin());
        enterpriseExamVo.setExamForm(examInfo.getExamForm());
        enterpriseExamVo.setExamType(examInfo.getExamType());
        enterpriseExamVo.setMergeType(String.valueOf(examInfo.getMergeType()));
        if (StrUtil.isNotEmpty(examInfo.getExamType())) {
            Optional<Classification> optional = classificationTree.stream().filter(item -> examInfo.getExamType().equals(item.getId())).findFirst();
            if (optional.isPresent()) {
                enterpriseExamVo.setExamTypeName(optional.get().getName());
            }
        }
        if (ExamFormEnums.FORM_EXAM_GROUP.getCode().equals(examInfo.getExamForm())
                && CommonEnums.EXAM_MERGE_TYPE_0.getCode().equals(String.valueOf(examInfo.getMergeType()))) {
            enterpriseExamVo.setScoreLine(iEnterpriseExamScoreLineSettingService.getScoreLineList(enterpriseExamVo.getExamId(), CommonEnums.SCORE_LINE_DIMENSION_2.getCode(), null));
        } else {
            enterpriseExamVo.setScoreLine(iEnterpriseExamScoreLineSettingService.getScoreLineList(enterpriseExamVo.getExamId(), CommonEnums.SCORE_LINE_DIMENSION_0.getCode(), null));
        }
        // 科目列表
        List<ExamSubjectVo> examSubjectVos = subjectMap.get(examInfo.getId());
        if (null != examSubjectVos) {
            for (ExamSubjectVo subjectVO : examSubjectVos) {
                List<EnterpriseScoreLineSaveParam> scoreLineList = iEnterpriseExamScoreLineSettingService.getScoreLineList(subjectVO.getExamInfoId(), CommonEnums.SCORE_LINE_DIMENSION_1.getCode(), subjectVO.getSubjectId());
                subjectVO.setScoreLine(scoreLineList);
            }
        }
        enterpriseExamVo.setSubjectList(examSubjectVos);
        return enterpriseExamVo;
    }

    @Override
    public List<ExamInfoVo> pageOtherExamInfoList(ExamPageParam examPageParam) {
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("examType", ExamTypeEnums.OTHER.getCode());
        queryMap.put("examForm", examPageParam.getExamForm());
        queryMap.put("examNameConfigName", examPageParam.getExamName());
        queryMap.put("year", examPageParam.getYear());
        queryMap.put("examStartDay", examPageParam.getExamStartDay());
        queryMap.put("examEndDay", examPageParam.getExamEndDay());
        queryMap.put("officeId", iBaseLoginService.getOfficeId());
        queryMap.put("deptIds", iBaseLoginService.getDeptIds());
        List<ExamInfoVo> examInfos = examInfoMapper.selectExamInfoByParms(queryMap);
        return examInfos;
    }

    @Override
    public List<OtherExamVo> pageOtherExamInfoListExchange(List<ExamInfoVo> list) {
        List<OtherExamVo> result = new ArrayList<>();
        List<String> examIds = new ArrayList();
        for (ExamInfoVo examInfo : list) {
            OtherExamVo otherExamVo = new OtherExamVo();
            otherExamVo.setExamId(examInfo.getId());
            otherExamVo.setExamName(examInfo.getExamNameConfigName());
            otherExamVo.setExamStartDay(DateUtil.format(examInfo.getExamStartDay(), "yyyy-MM-dd HH:mm"));
            otherExamVo.setExamEndDay(DateUtil.format(examInfo.getExamEndDay(), "yyyy-MM-dd HH:mm"));
            otherExamVo.setUpdateTime(DateUtil.format(examInfo.getUpdateTime(), "yyyy-MM-dd HH:mm"));
            otherExamVo.setYear(examInfo.getYear());
            otherExamVo.setOrigin(examInfo.getOrigin());
            result.add(otherExamVo);
            examIds.add(examInfo.getId());
        }
        Map<String, Integer> gradeCountMap = iEnterpriseExamineeSubjectGradeService.getExamineeSubjectGradeCountByExamIds(examIds);
        for (OtherExamVo examInfo : result) {
            examInfo.setGradeCount(gradeCountMap.get(examInfo.getExamId()) == null ? 0 : gradeCountMap.get(examInfo.getExamId()));
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class})
    public void insertEnterpriseExamInfo(EnterpriseExamSaveParam enterpriseExamSaveParam) {
        enterpriseExamineeInfoService.checkExamineeOrigin(enterpriseExamSaveParam.getId());
        enterpriseExamineeInfoService.checkExamineeArchived(enterpriseExamSaveParam.getId());
        String id = enterpriseExamSaveParam.getId();
        // 插入考试信息
        insertExamInfo(enterpriseExamSaveParam);

        // 插入科目、题干信息
        insertSubjectInfo(enterpriseExamSaveParam);

        //异步更新考生科目成绩合格
        if (StringUtils.isNotEmpty(id)) {
            threadPoolTaskExecutor.submit(new SyncExamineeSubjectInfoTask(enterpriseExamSaveParam.getId()));
        }
    }


    public class SyncExamineeSubjectInfoTask implements Runnable {
        private String examId;

        public SyncExamineeSubjectInfoTask(String examId) {
            this.examId = examId;
        }

        @Override
        public void run() {
            enterpriseExamineeInfoService.refreshEnterpriseExamineeSubjectQualified(examId);
        }
    }


    @Override
    @Transactional(rollbackFor = {RuntimeException.class})
    public void deleteEnterpriseExamInfoByIds(String ids) {
        String[] examIdArr = StrUtil.split(ids, ",").toArray(new String[0]);
        List<ExamInfo> examInfos = examInfoMapper.selectExamInfoByIds(examIdArr);
        for (ExamInfo examInfo : examInfos) {
            if (StringUtils.isNotEmpty(examInfo.getOrigin()) && "1".equals(examInfo.getOrigin())) {
                throw new CustomException("所选考试下存在云考试同步数据，不允许删除!");
            }
            // 是否关联证书
            ZsInfoVO zs = zsInfoService.examGetZsInfo(examInfo.getId());
            if (null != zs) {
                throw new CustomException("删除的考试已经关联证书，不允许删除!");
            }
        }

        Integer count = enterpriseExamineeSubjectGradeMapper.countArchivedExamineeSubjectGrade(examIdArr, null);
        if (null != count && count.intValue() > 0) {
            throw new CustomException("所选考试下存在已归档考生成绩数据，不允许删除!");
        }

        //关联考试需要解除关联
        List<ExamInfoVo> examInfoVos = new ArrayList<>();
        for (ExamInfo examInfo : examInfos) {
            if (ExamFormEnums.FORM_EXAM_GROUP.getCode().equals(examInfo.getExamForm())) {
                Map<String, Object> params = new HashedMap<>();
                params.put("relationId", examInfo.getId());
                examInfoVos.addAll(examInfoMapper.selectEnterpriseExamInfoByParms(params));
            } else {
                if (StrUtil.isNotEmpty(examInfo.getRelationId())) {
                    throw new CustomException("考试存在与考试组关联关系，不允许删除!");
                }
            }
        }
        if (CollectionUtil.isNotEmpty(examInfoVos)) {
            examInfoMapper.emptyBatchExamInfoRel(examInfoVos);
            // 调接口
            List<String> examIds = examInfoVos.stream().distinct().map(e -> e.getId()).collect(Collectors.toList());
            enterpriseGroupExamineeInfoService.updateExamExamineeQualified(examIds);
        }

        // 删除考试名称
        List<ExamInfo> examInfoDelete = examInfoMapper.selectExamInfoByIds(examIdArr);
        String[] nameIds = examInfoDelete.stream().map(ExamInfo::getExamNameConfigId).toArray(String[]::new);
        examNameConfigMapper.deleteExamNameConfigByIds(nameIds);

        if (ArrayUtil.isNotEmpty(examIdArr)) {
            // 删除科目info
            examSubjectInfoMapper.deleteExamSubjectInfoByExamInfoIds(examIdArr);
            //删除考生
            enterpriseExamineeInfoMapper.deleteEnterpriseExamineeInfoByIds(examIdArr);
            //删除成绩
            enterpriseExamineeSubjectGradeMapper.deleteEnterpriseExamineeSubjectGradeByExamIds(examIdArr);

        }

        // 删除考试info
        examInfoMapper.deleteExamInfoByIds(examIdArr);

        // 删除题干
        List<ExamSubjectVo> examSubjectVos = examSubjectInfoMapper.selectExamSubjectInfoByExamIds(examIdArr);
        String[] subjectIds = examSubjectVos.stream().map(ExamSubjectVo::getSubjectId).toArray(String[]::new);
        if (ArrayUtil.isNotEmpty(subjectIds)) {
            examStemInfoMapper.deleteExamStemInfoBySubjectIds(subjectIds);
        }


    }

    @Override
    public EnterpriseSubjectParam enterpriseExamSubjectDetail(String subjectId) {
        ExamSubjectVo examSubjectVo = examSubjectInfoMapper.selectExamSubjectById(subjectId);
        return changeSubjectVo(examSubjectVo);
    }

    ;

    @Override
    public EnterpriseExamSaveParam enterpriseExamDetail(String id) {
        EnterpriseExamSaveParam result = new EnterpriseExamSaveParam();
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("id", id);
        List<ExamInfoVo> examInfos = examInfoMapper.selectExamInfoByParms(queryMap);
        if (examInfos.size() > 0) {
            ExamInfoVo examInfoVo = examInfos.get(0);
            result.setId(examInfoVo.getId());
            result.setExamEndDay(DateUtil.formatDateTime(examInfoVo.getExamEndDay()));
            result.setExamStartDay(DateUtil.formatDateTime(examInfoVo.getExamStartDay()));
            result.setExamName(examInfoVo.getExamNameConfigName());
            result.setExamType(examInfoVo.getExamType());
            // 查询科目数据
            List<ExamSubjectVo> examSubjectVos = examSubjectInfoMapper.selectExamSubjectInfoByExamId(examInfoVo.getId());
            List<EnterpriseSubjectParam> EnterpriseSubjectList = new ArrayList<>();
            for (ExamSubjectVo examSubjectInfo : examSubjectVos) {
                EnterpriseSubjectList.add(changeSubjectVo(examSubjectInfo));
            }
            result.setEnterpriseSubjectList(EnterpriseSubjectList);
        }
        return result;
    }

    /**
     * 封装数据
     *
     * @param examSubjectInfo
     * @return
     */
    EnterpriseSubjectParam changeSubjectVo(ExamSubjectVo examSubjectInfo) {
        EnterpriseSubjectParam enterpriseSubjectParam = new EnterpriseSubjectParam();
        enterpriseSubjectParam.setId(examSubjectInfo.getSubjectId());
        enterpriseSubjectParam.setComparsionType(examSubjectInfo.getComparisonType());
        enterpriseSubjectParam.setFullScore(examSubjectInfo.getPaperFullMarks() == null ?
                null : examSubjectInfo.getPaperFullMarks().stripTrailingZeros().toPlainString());
        enterpriseSubjectParam.setRemarks(examSubjectInfo.getRemarks());
        enterpriseSubjectParam.setScoreLine(examSubjectInfo.getEligibilityCriteria() == null ?
                null : examSubjectInfo.getEligibilityCriteria().stripTrailingZeros().toPlainString());
        enterpriseSubjectParam.setSubjectName(examSubjectInfo.getSubjectName());

        // 组装题干信息
        List<EnterpriseStemParam> enterpriseStemList = new ArrayList<>();
        ExamStemInfo examStemInfoQuery = new ExamStemInfo();
        examStemInfoQuery.setSubjectId(examSubjectInfo.getSubjectId());
        List<ExamStemInfo> examStemInfos = examStemInfoMapper.selectExamStemInfoList(examStemInfoQuery);
        for (ExamStemInfo examStemInfo : examStemInfos) {
            EnterpriseStemParam enterpriseStemParam = new EnterpriseStemParam();
            enterpriseStemParam.setId(examStemInfo.getId());
            enterpriseStemParam.setTitleName(examStemInfo.getName());
            enterpriseStemParam.setTotalScore(examStemInfo.getTotalPoints().stripTrailingZeros().toPlainString());
            enterpriseStemList.add(enterpriseStemParam);
        }
        enterpriseSubjectParam.setEnterpriseStemList(enterpriseStemList);
        return enterpriseSubjectParam;
    }

    @Override
    public void examTypeChange(ExamTypeChangeParam examTypeChangeParam) {
        ExamInfo examInfo = examInfoMapper.selectExamInfoById(examTypeChangeParam.getExamId());
        if (null == examInfo) {
            throw new CustomException("考试不存在");
        }
        examInfo.setExamType(examTypeChangeParam.getType());
        examInfoMapper.updateExamInfo(examInfo);
    }

    //转换EnterpriseExamInfo与ExamInfo
    private void insertExamInfo(EnterpriseExamSaveParam enterpriseExamSaveParam) {
        ExamInfo examInfo = new ExamInfo();
        // 查询是否存在同名考试
        ExamNameConfig queryCondition = new ExamNameConfig();
        queryCondition.setExamType(enterpriseExamSaveParam.getExamType());
        queryCondition.setName(enterpriseExamSaveParam.getExamName());
        queryCondition.setOfficeId(iBaseLoginService.getOfficeId());
        List<ExamNameConfig> list = examNameConfigMapper.selectExamNameConfigList(queryCondition);
        ExamNameConfig examNameConfig;
        if (list.size() < 1) {
            examNameConfig = new ExamNameConfig();
            examNameConfig.setOfficeId(iBaseLoginService.getOfficeId());
            examNameConfig.setDeptId(100L);
            examNameConfig.setId(IdUtils.generateId());
            examNameConfig.setExamNameCode(examNameConfig.getId());
            examNameConfig.setExamType(enterpriseExamSaveParam.getExamType());
            examNameConfig.setName(enterpriseExamSaveParam.getExamName());
            examNameConfig.setCreateBy(iBaseLoginService.getSysUser().getName());
            examNameConfig.setCreateTime(DateUtils.getNowDate());
            examNameConfig.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examNameConfig.setUpdateTime(DateUtils.getNowDate());
            examNameConfigMapper.insertExamNameConfig(examNameConfig);

            // 如果是修改考试,把老考试名删除
            if (StrUtil.isNotEmpty(enterpriseExamSaveParam.getId())) {
                ExamInfo examInfoOld = examInfoMapper.selectExamInfoById(enterpriseExamSaveParam.getId());
                examNameConfigMapper.deleteExamNameConfigById(examInfoOld.getExamNameConfigId());
            }
        } else {
            examNameConfig = list.get(0);
            if (StringUtils.isNotEmpty(enterpriseExamSaveParam.getId())) {
                ExamInfo exam = examInfoMapper.selectExamInfoById(enterpriseExamSaveParam.getId());
                if (!exam.getExamNameConfigId().equals(examNameConfig.getId())) {
                    throw new CustomException("考试名称已经存在，不允许重复添加!");
                }
            } else {
                throw new CustomException("考试名称已经存在，不允许重复添加!");
            }

        }

        // 转换考试信息
        examInfo.setExamNameConfigId(examNameConfig.getId());
        examInfo.setYear(enterpriseExamSaveParam.getExamStartDay() != null
                && enterpriseExamSaveParam.getExamStartDay().length() < 4 ? "" : enterpriseExamSaveParam.getExamStartDay().substring(0, 4));
        examInfo.setExamType(enterpriseExamSaveParam.getExamType());
        examInfo.setDeptId(iBaseLoginService.getDeptId());
        examInfo.setOfficeId(iBaseLoginService.getOfficeId());
        if (StringUtils.isEmpty(enterpriseExamSaveParam.getId())) {
            examInfo.setId("KS" + IdUtils.generateId());
            examInfo.setCreateBy(iBaseLoginService.getSysUser().getName());
            examInfo.setCreateTime(DateUtils.getNowDate());
            examInfo.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examInfo.setUpdateTime(DateUtils.getNowDate());
            examInfoMapper.insertExamInfo(examInfo);
            enterpriseExamSaveParam.setId(examInfo.getId());
        } else {
            examInfo.setId(enterpriseExamSaveParam.getId());
            examInfo.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examInfo.setUpdateTime(DateUtils.getNowDate());
            examInfoMapper.updateExamInfo(examInfo);
        }
    }

    // 插入科目信息
    @Override
    @Transactional(rollbackFor = {RuntimeException.class})
    public void insertSubjectInfo(EnterpriseExamSaveParam enterpriseExamSaveParam) {
        // 校验
        enterpriseExamineeInfoService.checkExamineeOrigin(enterpriseExamSaveParam.getId());
        enterpriseExamineeInfoService.checkExamineeArchived(enterpriseExamSaveParam.getId());

        List<EnterpriseSubjectParam> enterpriseSubjectList = enterpriseExamSaveParam.getEnterpriseSubjectList();
        // 判断传入参数重复
        List<String> subjectListDistinct = enterpriseSubjectList.stream().map(EnterpriseSubjectParam::getSubjectName).distinct().collect(Collectors.toList());
        if (subjectListDistinct.size() < enterpriseSubjectList.size()) {
            throw new CustomException("同一考试下科目不能相同，请检查!");
        }

        for (EnterpriseSubjectParam subject : enterpriseSubjectList) {
            if (StringUtils.isEmpty(subject.getSubjectName())) {
                throw new CustomException("科目名称不能为空!");
            }
            if (StringUtils.isEmpty(subject.getFullScore())) {
                throw new CustomException("科目满分不能为空!");
            }
			/*if(StringUtils.isEmpty(subject.getScoreLine())){
				throw new CustomException("科目分数线不能为空!");
			}*/

            // 是否删除记录
            if (StringUtils.isNotEmpty(subject.getId()) && CommonEnums.DATA_DEL_FLAG_D.getCode().equals(subject.getDelFlag())) {
                iExamSubjectInfoService.deleteEnterpriseSubjectById(subject.getId());
                continue;
            }

            // 处理科目
            ExamSubjectInfo subjectInfo = new ExamSubjectInfo();
            subjectInfo.setComparisonType(subject.getComparsionType());
            // subjectInfo.setEligibilityCriteria(new BigDecimal(subject.getScoreLine()));
            subjectInfo.setExamInfoId(enterpriseExamSaveParam.getId());
            subjectInfo.setPaperFullMarks(new BigDecimal(subject.getFullScore()));
            subjectInfo.setRemarks(subject.getRemarks());
            subjectInfo.setCreateBy(iBaseLoginService.getSysUser().getName());
            subjectInfo.setCreateTime(DateUtils.getNowDate());
            subjectInfo.setUpdateBy(iBaseLoginService.getSysUser().getName());
            subjectInfo.setUpdateTime(DateUtils.getNowDate());
            subjectInfo.setDeptId(iBaseLoginService.getDeptId());
            subjectInfo.setOfficeId(iBaseLoginService.getOfficeId());

            // 科目分数线限制
			/*if(CommonEnums.COMPARISON_TYPE_0.getCode().equals(subject.getComparsionType())
					&& new BigDecimal(subject.getScoreLine()).compareTo(new BigDecimal(subject.getFullScore())) > -1){
				throw new CustomException("科目分数线必须小于科目总分!");
			}
			if(CommonEnums.COMPARISON_TYPE_1.getCode().equals(subject.getComparsionType())
					&& new BigDecimal(subject.getScoreLine()).compareTo(new BigDecimal(subject.getFullScore())) == 1){
				throw new CustomException("科目分数线必须小于等于科目总分!");
			}*/

            // 科目名称判重
            List<ExamSubjectVo> subjectNameList = examSubjectInfoMapper.selectExamSubjectByName(subject.getSubjectName(), enterpriseExamSaveParam.getId());
            if (StringUtils.isEmpty(subject.getId()) && subjectNameList.size() > 0) {
                throw new CustomException("同一考试下科目不能相同，请检查!");
            }
            // 修改科目判重
            if (CollectionUtils.isNotEmpty(subjectNameList) && StringUtils.isNotEmpty(subject.getId())
                    && !subjectNameList.get(0).getSubjectId().equals(subject.getId())) {
                throw new CustomException("同一考试下科目不能相同，请检查!");
            }

            // 新增科目
            ExamSubjectNameConfig examSubjectNameConfig = new ExamSubjectNameConfig();
            examSubjectNameConfig.setId(IdUtils.generateId());
            examSubjectNameConfig.setName(subject.getSubjectName());
            examSubjectNameConfig.setCreateBy(iBaseLoginService.getSysUser().getName());
            examSubjectNameConfig.setCreateTime(DateUtils.getNowDate());
            examSubjectNameConfig.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examSubjectNameConfig.setUpdateTime(DateUtils.getNowDate());
            examSubjectNameConfig.setOfficeId(iBaseLoginService.getOfficeId());
            examSubjectNameConfig.setDeptId(iBaseLoginService.getDeptId());
            examSubjectNameConfigMapper.insertExamSubjectNameConfig(examSubjectNameConfig);

            // 插入科目
            subjectInfo.setExamSubjectNameId(examSubjectNameConfig.getId());

            if (StringUtils.isEmpty(subject.getId())) {
                subjectInfo.setId("KM" + IdUtils.generateId());
                examSubjectInfoMapper.insertExamSubjectInfo(subjectInfo);
            } else {
                subjectInfo.setId(subject.getId());
                examSubjectInfoMapper.updateExamSubjectInfo(subjectInfo);
            }

            // 处理题干
            List<EnterpriseStemParam> enterpriseStemList = subject.getEnterpriseStemList();
            BigDecimal stemMarks = new BigDecimal(0);

            // 题目重名处理
            List<String> stemName = new ArrayList<>();

            for (EnterpriseStemParam enterpriseStemParam : enterpriseStemList) {
                // 是否删除记录
                if (StringUtils.isNotEmpty(enterpriseStemParam.getId()) && CommonEnums.DATA_DEL_FLAG_D.getCode().equals(enterpriseStemParam.getDelFlag())) {
                    // 删除题干
                    examStemInfoMapper.deleteExamStemInfoById(enterpriseStemParam.getId());
                    continue;
                } else {
                    if (stemName.contains(enterpriseStemParam.getTitleName())) {
                        throw new CustomException("同一科目下题目名称不能相同!");
                    }
                    stemName.add(enterpriseStemParam.getTitleName());
                }

                ExamStemInfo examStemInfo = new ExamStemInfo();
                examStemInfo.setName(enterpriseStemParam.getTitleName());
                BigDecimal bigDecimal = new BigDecimal(enterpriseStemParam.getTotalScore());
                stemMarks = stemMarks.add(bigDecimal);
                examStemInfo.setTotalPoints(bigDecimal);
                examStemInfo.setSubjectId(subjectInfo.getId());
                examStemInfo.setDeptId(iBaseLoginService.getDeptId());
                examStemInfo.setOfficeId(iBaseLoginService.getOfficeId());
                if (StringUtils.isEmpty(enterpriseStemParam.getId())) {
                    examStemInfo.setId("TG" + IdUtils.generateId());
                    examStemInfoMapper.insertExamStemInfo(examStemInfo);
                } else {
                    examStemInfo.setId(enterpriseStemParam.getId());
                    examStemInfoMapper.updateExamStemInfo(examStemInfo);
                }
            }
            if (CollectionUtils.isNotEmpty(enterpriseStemList) && stemMarks.compareTo(subjectInfo.getPaperFullMarks()) != 0) {
                throw new CustomException("科目下题目总分相加需与试卷满分不相等，请检查!");
            }
        }

        //异步更新考生科目成绩合格
        if (StringUtils.isNotEmpty(enterpriseExamSaveParam.getId())) {
            threadPoolTaskExecutor.submit(new SyncExamineeSubjectInfoTask(enterpriseExamSaveParam.getId()));
        }
    }


    @Override
    public ExamQualifiedStatusVo getExamQualifiedStatus(String examId, String subjectId) {
        ExamQualifiedStatusVo vo = new ExamQualifiedStatusVo();
        if (StringUtils.isEmpty(examId)) {
            return vo;
        }
        ExamInfo examInfo = examInfoMapper.selectExamInfoById(examId);
        if (null == examInfo) {
            return vo;
        }
        List<String> ids = null;
        if (StringUtils.isNotEmpty(subjectId)) {
            //考试组
            if (ExamFormEnums.FORM_EXAM_GROUP.getCode().equals(examInfo.getExamForm())) {
                if (CommonEnums.EXAM_MERGE_TYPE_1.getCode().equals(String.valueOf(examInfo.getMergeType()))) {
                    ids = iEnterpriseExamScoreLineSettingService.selectScoreLineIds(examId, CommonEnums.SCORE_LINE_TYPE_2.getCode(), CommonEnums.SCORE_LINE_DIMENSION_1.getCode(), subjectId);
                } else {
                    ids = iEnterpriseExamScoreLineSettingService.selectScoreLineIds(subjectId, CommonEnums.SCORE_LINE_TYPE_2.getCode(), CommonEnums.SCORE_LINE_DIMENSION_0.getCode());
                    subjectId = "";
                }
                //普通考试科目
            } else {
                ids = iEnterpriseExamScoreLineSettingService.selectScoreLineIds(examId, CommonEnums.SCORE_LINE_TYPE_2.getCode(), CommonEnums.SCORE_LINE_DIMENSION_1.getCode());

            }
        } else {
            //考试组
            if (ExamFormEnums.FORM_EXAM_GROUP.getCode().equals(examInfo.getExamForm())) {

                if (CommonEnums.EXAM_MERGE_TYPE_1.getCode().equals(String.valueOf(examInfo.getMergeType()))) {
                    ids = iEnterpriseExamScoreLineSettingService.selectScoreLineIds(examId, CommonEnums.SCORE_LINE_TYPE_2.getCode(), CommonEnums.SCORE_LINE_DIMENSION_0.getCode());
                } else {
                    ids = iEnterpriseExamScoreLineSettingService.selectScoreLineIds(examId, CommonEnums.SCORE_LINE_TYPE_2.getCode(), CommonEnums.SCORE_LINE_DIMENSION_2.getCode());
                }

                //普通考试
            } else {
                ids = iEnterpriseExamScoreLineSettingService.selectScoreLineIds(examId, CommonEnums.SCORE_LINE_TYPE_2.getCode(), CommonEnums.SCORE_LINE_DIMENSION_0.getCode());

            }

        }
        Set<String> regionNames = null;
        if (CollectionUtils.isNotEmpty(ids)) {
            regionNames = new HashSet(enterpriseExamScoreLineSettingSubMapper.selectRegionNameBySettingIds(ids.toArray(new String[ids.size()]), subjectId));
        }

        List<SelectVo> selectVos = null;
        if (regionNames != null) {
            regionNames = regionNames.stream().filter(item -> item != null).collect(Collectors.toSet());
        }
        if (CollectionUtils.isEmpty(regionNames)) {
            selectVos = new ArrayList<>(2);
            SelectVo selectVo = new SelectVo();
            selectVo.setKey(CommonEnums.QUALIFIED_STATUS_Y.getCode());
            selectVo.setValue(CommonEnums.QUALIFIED_STATUS_Y.getDesc());
            selectVos.add(selectVo);
            selectVo = new SelectVo();
            selectVo.setKey(CommonEnums.QUALIFIED_STATUS_N.getCode());
            selectVo.setValue(CommonEnums.QUALIFIED_STATUS_N.getDesc());
            selectVos.add(selectVo);
        }

        if (CollectionUtils.isNotEmpty(regionNames)) {
            vo.setRegionName(regionNames);
            vo.setQualifiedStatus(null);
        } else {
            vo.setRegionName(null);
            vo.setQualifiedStatus(selectVos);
        }
        return vo;
    }


    @Override
    public List<ExamInfoExternalVo> getExamInfoExternalVosByOfficeId(String officeId, Integer bindingStatus, String examName) {
        return examInfoMapper.getExamInfoExternalVosByOfficeId(officeId, bindingStatus, examName);
    }

    @Override
    public List<ExamInfoExternalVo> getExamInfoExternalVosByExamIds(List<String> examIds) {
        return examInfoMapper.getExamInfoExternalVosByExamIds(examIds.toArray(new String[examIds.size()]));
    }

    @Override
    public ExamInfo selectExamById(String id) {
        return examInfoMapper.selectExamInfoById(id);
    }

    @Override
    public List<ExamConfigNameVo> getExamNameList(ExamNameQueryParam examNameQueryParam) {
        String examType = examNameQueryParam.getExamType();
        String examForm = examNameQueryParam.getExamForm();
        List<Classification> classificationList;
        if ("all".equals(examType)) {
            classificationList = classificationService.getClassificationList();
        } else {
            classificationList = classificationService.getChildList(examType);
        }
        String[] examTypes = classificationList.stream().map(item -> item.getId()).toArray(String[]::new);
        List<Map<String, String>> list = examInfoMapper.getEnterpriseExamNameList(examForm, examTypes, examNameQueryParam.getType(), iBaseLoginService.getOfficeId(), examNameQueryParam.getDeptIds());
        List<ExamConfigNameVo> examNameVoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (Map<String, String> map : list) {
                ExamConfigNameVo vo = new ExamConfigNameVo();
                vo.setId(map.get("id"));
                vo.setName(map.get("name") + "(" + map.get("examNameCode") + ")");
                vo.setType("0");
                vo.setOrigin(String.valueOf(map.get("origin")));
                vo.setName(map.get("name") + "(" + map.get("id") + ")");
                vo.setMergeType(String.valueOf(map.get("mergeType")));
                String taskId = map.get("taskId");
                if (StrUtil.isNotEmpty(taskId)) {
                    vo.setVirtualFlag(true);
                } else {
                    vo.setVirtualFlag(false);
                }

                // 是否绑定了证书
                Integer certificateBindingNum = zsInfoService.lambdaQuery()
                        .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                        .eq(ZsInfo::getExamId, vo.getId())
                        .eq(ZsInfo::getCertificatePublishType, CertificatePublishTypeEnums.RELATION_CJ_PUBLISH.getCode())
                        .count();
                vo.setHasCertificate(certificateBindingNum > CommonConstant.ZERO);

                examNameVoList.add(vo);
            }
        }
        return examNameVoList;
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class})
    public void examMerge(ExamMergeParam examMergeParam) {
        // 保存考试名称
        ExamNameConfig examNameConfig = new ExamNameConfig();
        if (StrUtil.isEmpty(examMergeParam.getExamId())) {
            examNameConfig.setOfficeId(iBaseLoginService.getOfficeId());
            examNameConfig.setDeptId(100L);
            examNameConfig.setId(IdUtils.generateId());
            examNameConfig.setExamNameCode(examNameConfig.getId());
            examNameConfig.setCreateBy(iBaseLoginService.getSysUser().getName());
            examNameConfig.setCreateTime(DateUtils.getNowDate());
            examNameConfig.setExamType(examMergeParam.getExamType());
            examNameConfig.setName(examMergeParam.getExamName());
            examNameConfig.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examNameConfig.setUpdateTime(DateUtils.getNowDate());
            examNameConfigMapper.insertExamNameConfig(examNameConfig);
        } else {
            ExamInfo examInfo = examInfoMapper.selectExamInfoById(examMergeParam.getExamId());
            if (examInfo != null) {
                examNameConfig = examNameConfigMapper.selectById(examInfo.getExamNameConfigId());
                examNameConfig.setExamType(examMergeParam.getExamType());
                examNameConfig.setName(examMergeParam.getExamName());
                examNameConfig.setUpdateBy(iBaseLoginService.getSysUser().getName());
                examNameConfig.setUpdateTime(DateUtils.getNowDate());
                examNameConfigMapper.updateById(examNameConfig);
            }
        }

        // 保存考试信息
        ExamInfo examInfo = new ExamInfo();
        if (StrUtil.isEmpty(examMergeParam.getExamId())) {
            examInfo.setExamNameConfigId(examNameConfig.getId());
            examInfo.setYear(examMergeParam.getExamStartDay() != null
                    && examMergeParam.getExamStartDay().length() < 4 ? "" : examMergeParam.getExamStartDay().substring(0, 4));
            examInfo.setExamStartDay(DateUtil.parseLocalDateTime(examMergeParam.getExamStartDay()));
            examInfo.setExamEndDay(DateUtil.parseLocalDateTime(examMergeParam.getExamEndDay()));
            examInfo.setId("KS" + IdUtils.generateId());
            examInfo.setExamForm(ExamFormEnums.FORM_EXAM_GROUP.getCode());
            examInfo.setExamType(examMergeParam.getExamType());
            examInfo.setDeptId(iBaseLoginService.getDeptId());
            examInfo.setOfficeId(iBaseLoginService.getOfficeId());
            examInfo.setCreateBy(iBaseLoginService.getSysUser().getName());
            examInfo.setCreateTime(DateUtils.getNowDate());
            examInfo.setMergeType(Integer.parseInt(examMergeParam.getType()));
            examInfo.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examInfo.setUpdateTime(DateUtils.getNowDate());
            examInfo.setRemarks(examMergeParam.getRemarks());
            examInfoMapper.insertExamInfo(examInfo);
        } else {
            examInfo = examInfoMapper.selectExamInfoById(examMergeParam.getExamId());
            examInfo.setExamType(examMergeParam.getExamType());
            examInfo.setYear(examMergeParam.getExamStartDay() != null
                    && examMergeParam.getExamStartDay().length() < 4 ? "" : examMergeParam.getExamStartDay().substring(0, 4));
            examInfo.setUpdateBy(iBaseLoginService.getSysUser().getName());
            examInfo.setUpdateTime(DateUtils.getNowDate());
            examInfo.setRemarks(examMergeParam.getRemarks());

            // 删除关联关系
            Map<String, Object> params = new HashedMap<>();
            params.put("relationId", examInfo.getId());
            List<ExamInfoVo> examInfoVos = new ArrayList<>();
            examInfoVos.addAll(examInfoMapper.selectEnterpriseExamInfoByParms(params));
            if (CollUtil.isNotEmpty(examInfoVos)) {
                examInfoMapper.emptyBatchExamInfoRel(examInfoVos);
            }
        }

        // 合并信息
        List<ExamMergeItem> examMergeItemList = examMergeParam.getExamMergeItemList();
        String[] examIds = examMergeParam.getMergeExamIds().split(",");
        List<ExamInfo> examInfos = examInfoMapper.selectExamInfoByIds(examIds);
        for (ExamInfo item : examInfos) {
            if (StrUtil.isNotEmpty(item.getRelationId())) {
                throw new CustomException("已关联的考试不允许再次关联!");
            }
            item.setRelationId(examInfo.getId());
            examInfoMapper.updateExamInfo(item);
        }
        if (examMergeParam.getType().equals(CommonEnums.EXAM_MERGE_TYPE_1.getCode())) {
            mergeSubject(examInfo, examMergeItemList, StrUtil.isNotEmpty(examMergeParam.getExamId()));
        }

    }


    /**
     * 合并科目考试组需要合并科目
     *
     * @param examInfo
     * @param oldDel
     * @param examMergeItemList
     */
    private void mergeSubject(ExamInfo examInfo, List<ExamMergeItem> examMergeItemList, boolean oldDel) {
        // 更新，直接删旧
        if (oldDel) {
            // 需要更新的科目
            List<String> subjectIdInput = examMergeItemList.stream().map(item -> item.getSubjectId()).collect(Collectors.toList());
            // 已存在科目id
            List<String> subjectIdExsit = examSubjectInfoMapper.selectExamSubjectInfoByExamId(examInfo.getId()).stream().map(item -> item.getSubjectId()).collect(Collectors.toList());
            String[] subjectIdRemove = subjectIdExsit.stream().filter(item -> !subjectIdInput.contains(item)).toArray(String[]::new);

            if (subjectIdRemove.length > 0) {
                // 变更考试组科目前先校验考试组下有没有归档数据，有则不允许修改
                List<EnterpriseExamineeSubjectGrade> archiveData = enterpriseExamineeSubjectGradeMapper.selectArchivedExamineeSubjectGradeBySubjecIds(examInfo.getId(), subjectIdRemove);
                if (CollectionUtils.isNotEmpty(archiveData)) {
                    throw new CustomException("修改科目下存在已归档考生成绩数据，不允许修改!");
                }

                String examId = examInfo.getId();
                List<ExamSubjectVo> examSubjectVos = examSubjectInfoMapper.selectExamSubjectListByIds(subjectIdRemove);
                // 删除科目名称
                examSubjectVos.stream().forEach(item -> {
                    examSubjectNameConfigMapper.deleteById(item.getExamSubjectNameId());
                    // 删除科目
                    examSubjectInfoMapper.deleteExamSubjectInfoById(item.getSubjectId());
                    // 删除考生成绩
                    enterpriseExamineeSubjectGradeMapper.deleteEnterpriseExamineeSubjectGradeByExamId(examId, item.getSubjectId());
                    // 删除分数线
                    iEnterpriseExamScoreLineSettingService.deleteScoreLineBySubjectId(item.getSubjectId());
                });

                // 删除题干
                String[] subejctIds = examSubjectVos.stream().map(item -> item.getSubjectId()).toArray(String[]::new);
                examStemInfoMapper.deleteExamStemInfoBySubjectIds(subejctIds);

                // 如果没有成绩则删除该考生
                EnterpriseExamineeSubjectGrade queryCond = new EnterpriseExamineeSubjectGrade();
                queryCond.setExamId(examInfo.getId());
                List<EnterpriseExamineeSubjectGrade> enterpriseExamineeSubjectGrades = enterpriseExamineeSubjectGradeMapper.selectEnterpriseExamineeSubjectGradeList(queryCond);

                EnterpriseExamineeInfo enterpriseExamineeInfoParams = new EnterpriseExamineeInfo();
                enterpriseExamineeInfoParams.setExamId(examInfo.getId());
                List<EnterpriseExamineeInfo> existingEnterpriseExamineeInfolist = enterpriseExamineeInfoMapper.selectEnterpriseExamineeInfoList(enterpriseExamineeInfoParams);
                // 删除没有成绩的考生
                List<String> examnieeIdHaveGradeList = enterpriseExamineeSubjectGrades.stream().map(item -> item.getExamineeId()).distinct().collect(Collectors.toList());
                List<String> examnieeIdExistList = existingEnterpriseExamineeInfolist.stream().map(item -> item.getId()).distinct().collect(Collectors.toList());

                for (String examnieeId : examnieeIdExistList) {
                    if (!examnieeIdHaveGradeList.contains(examnieeId)) {
                        // 删除考生
                        enterpriseExamineeInfoMapper.deleteEnterpriseExamineeInfoById(examnieeId);
                    }
                }
            }

            // 只保存数据库里没有的
            examMergeItemList = examMergeItemList.stream().filter(item -> !subjectIdExsit.contains(item.getSubjectId())).collect(Collectors.toList());
        }

        Map<String, String> examineeIdOldNew = new HashedMap<>();
        for (ExamMergeItem examMergeItem : examMergeItemList) {
            String subjectIds = examMergeItem.getMergeSubjectIds();
            String subjectName = examMergeItem.getMergeSubjectName();

            // 查询科目
            List<ExamSubjectInfo> subjectList = examSubjectInfoMapper.selectExamSubjectInfoByIds(CollectionUtil.newArrayList(subjectIds.split(",")));
            List<EnterpriseExamineeSubjectGrade> enterpriseExamineeSubjectGradeList = enterpriseExamineeSubjectGradeMapper.selectGradeByExamIdAndSubjectIds(CollectionUtil.newArrayList(subjectIds.split(",")));

            if (CollectionUtil.isNotEmpty(subjectList)) {
                // 判断科目总分否相同
                int sizeDistinct = subjectList.stream().map(item -> item.getPaperFullMarks()).distinct().collect(Collectors.toList()).size();
                if (sizeDistinct != 1) {
                    throw new CustomException("请选择相同满分分值的科目进行合并!");
                }

                // 合并考生信息
                List<String> examieeIdList = enterpriseExamineeSubjectGradeList.stream().map(EnterpriseExamineeSubjectGrade::getExamineeId).distinct().collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(examieeIdList)) {
                    List<EnterpriseExamineeInfo> enterpriseExamineeInfoList = enterpriseExamineeInfoMapper.selectEnterpriseExamineeInfoByIds(examieeIdList);
                    // 从这里查找数据库中已存在的考生id，避免重复新增，导致对应不上
                    List<EnterpriseExamineeInfo> enterpriseExamineeInfos = enterpriseExamineeInfoMapper.selectEnterpriseExamineeInfoByExamId(examInfo.getId());
                    Map<String, String> examnieeMap = enterpriseExamineeInfos.stream().filter(item -> StrUtil.isNotEmpty(item.getIdcard()) && StrUtil.isNotEmpty(item.getName()))
                            .collect(Collectors.toMap(item -> item.getIdcard() + item.getName(), item -> item.getId()));
                    if (CollectionUtil.isNotEmpty(enterpriseExamineeInfoList)) {
                        // 插入考生
                        for (EnterpriseExamineeInfo item : enterpriseExamineeInfoList) {
                            item.setExamId(examInfo.getId());
                            String oldId = item.getId();
                            if (examineeIdOldNew.get(oldId) == null) {
                                if (MapUtil.isEmpty(examnieeMap) || examnieeMap.get(item.getIdcard() + item.getName()) == null) {
                                    item.setId(IdUtils.generateId());
                                } else {
                                    item.setId(examnieeMap.get(item.getIdcard() + item.getName()));
                                }
                                examineeIdOldNew.put(oldId, item.getId());
                            } else {
                                item.setId(examineeIdOldNew.get(oldId));
                            }
                        }
                        enterpriseExamineeInfoMapper.insertBatchEnterpriseExamineeInfoMerge(enterpriseExamineeInfoList);
                    }
                }

                // 新增科目名称
                ExamSubjectNameConfig examSubjectNameConfig = new ExamSubjectNameConfig();
                examSubjectNameConfig.setId(IdUtils.generateId());
                examSubjectNameConfig.setName(subjectName);
                examSubjectNameConfig.setCreateBy(iBaseLoginService.getSysUser().getName());
                examSubjectNameConfig.setCreateTime(DateUtils.getNowDate());
                examSubjectNameConfig.setUpdateBy(iBaseLoginService.getSysUser().getName());
                examSubjectNameConfig.setUpdateTime(DateUtils.getNowDate());
                examSubjectNameConfig.setOfficeId(iBaseLoginService.getOfficeId());
                examSubjectNameConfig.setDeptId(iBaseLoginService.getDeptId());
                examSubjectNameConfigMapper.insertExamSubjectNameConfig(examSubjectNameConfig);

                // 新增科目
                ExamSubjectInfo subjectInfo = new ExamSubjectInfo();
                subjectInfo.setId("KM" + IdUtils.generateId());
                subjectInfo.setExamInfoId(examInfo.getId());
                subjectInfo.setExamSubjectNameId(examSubjectNameConfig.getId());
                // 总分一样，取其中一个就行了
                subjectInfo.setPaperFullMarks(subjectList.get(0).getPaperFullMarks());
                subjectInfo.setCreateBy(iBaseLoginService.getSysUser().getName());
                subjectInfo.setCreateTime(DateUtils.getNowDate());
                subjectInfo.setUpdateBy(iBaseLoginService.getSysUser().getName());
                subjectInfo.setUpdateTime(DateUtils.getNowDate());
                subjectInfo.setDeptId(iBaseLoginService.getDeptId());
                subjectInfo.setOfficeId(iBaseLoginService.getOfficeId());
                examSubjectInfoMapper.insertExamSubjectInfo(subjectInfo);

                // 更新关联科目id
                subjectList.stream().forEach(item -> {
                    item.setRelationId(subjectInfo.getId());
                });
                if (CollectionUtil.isNotEmpty(subjectList)) {
                    examSubjectInfoMapper.updataBatchSubjectInfo(subjectList);
                }

                // 合并题干信息
                List<ExamStemInfo> examStemInfList = examStemInfoMapper.selectExamStemInfoBySubjectIds(CollectionUtil.newArrayList(subjectIds.split(",")));
                //插入题干
                Map<String, String> stemIdOldNew = new HashedMap<>();
                examStemInfList.stream().forEach(item -> {
                    String oldId = item.getId();
                    item.setId(IdUtils.generateId());
                    stemIdOldNew.put(oldId, item.getId());
                    item.setSubjectId(subjectInfo.getId());
                });
                if (CollectionUtil.isNotEmpty(examStemInfList)) {
                    examStemInfoMapper.insertBatchExamStemInfo(examStemInfList);
                }

                // 插入考生成绩
                for (EnterpriseExamineeSubjectGrade item : enterpriseExamineeSubjectGradeList) {
                    item.setId(IdUtils.generateId());
                    if (StrUtil.isNotEmpty(item.getStemId())) {
                        item.setStemId(stemIdOldNew.get(item.getStemId()));
                    }
                    item.setExamId(examInfo.getId());
                    item.setSubjectId(subjectInfo.getId());
                    item.setExamineeId(examineeIdOldNew.get(item.getExamineeId()));
                }
                if (CollectionUtil.isNotEmpty(enterpriseExamineeSubjectGradeList)) {
                    enterpriseExamineeSubjectGradeMapper.insertBatchEnterpriseExamineeSubjectGradeMerge(enterpriseExamineeSubjectGradeList);
                }
            }
        }

        // 重复子考试考生成绩合并
        gradeMerge(examInfo.getId());
    }

    /**
     * 不同子考试下的同一个人成绩合并成一条
     *
     * @param examId
     */
    public void gradeMerge(String examId) {
        EnterpriseExamineeInfo queryCond = new EnterpriseExamineeInfo();
        queryCond.setExamId(examId);
        List<EnterpriseExamineeInfo> enterpriseExamineeInfos = enterpriseExamineeInfoService.selectEnterpriseExamineeInfoList(queryCond);
        Map<String, Long> collect = enterpriseExamineeInfos.stream().collect(Collectors.groupingBy(item -> item.getName() + "_" + item.getIdcard(), Collectors.counting()));
        collect.forEach((key, value) -> {
            if (value > 1) {
                queryCond.setName(key.split("_")[0]);
                queryCond.setIdcard(key.split("_")[1]);
                List<EnterpriseExamineeInfo> examineeInfos = enterpriseExamineeInfoService.selectEnterpriseExamineeInfoListRealName(queryCond);
                // 取第一个人考生id
                String examineeId = examineeInfos.get(0).getId();

                // 查询成绩数据
                Map<String, Object> parms = new HashedMap<>();
                parms.put("examId", examId);
                parms.put("examineeIds", examineeInfos.stream().map(item -> item.getId()).toArray(String[]::new));
                List<EnterpriseExamineeSubjectGrade> enterpriseExamineeExamGradeVos = enterpriseExamineeSubjectGradeMapper.selectEnterpriseSubjectExamineeByParms2(parms);
                // 更新成绩数据
                for (EnterpriseExamineeSubjectGrade item : enterpriseExamineeExamGradeVos) {
                    item.setExamineeId(examineeId);
                }
                enterpriseExamineeSubjectGradeMapper.updateBatchEnterpriseExamineeSubjectGrade(enterpriseExamineeExamGradeVos);

                // 重复的考生删除
                int index = 1;
                for (EnterpriseExamineeInfo item : examineeInfos) {
                    if (index == 1) {
                        index += 1;
                        continue;
                    }
                    enterpriseExamineeInfoMapper.delete(new LambdaQueryWrapper<EnterpriseExamineeInfo>().eq(EnterpriseExamineeInfo::getId, item.getId()));
                }
            }
        });
    }

    @Override
    public List<ExamInfoVo> getSubExamList(String examId) {
        ExamInfo examInfo = examInfoMapper.selectExamInfoById(examId);
        if (null == examInfo.getMergeType() || CommonEnums.EXAM_MERGE_TYPE_1.getCode().equals(String.valueOf(examInfo.getMergeType()))) {
            List<ExamSubjectVo> examSubjectVos = examSubjectInfoMapper.selectExamSubjectInfoByExamId(examId);
            if (CollectionUtils.isEmpty(examSubjectVos)) {
                return Collections.EMPTY_LIST;
            }
            List<ExamInfoVo> examInfoVos = new ArrayList<>(1);
            for (ExamSubjectVo examSubjectVo : examSubjectVos) {
                ExamInfoVo examInfoVo = new ExamInfoVo();
                examInfoVo.setId(examSubjectVo.getSubjectId());
                examInfoVo.setExamNameConfigName(examSubjectVo.getSubjectName());
                examInfoVo.setExamForm(examInfo.getExamForm());
                examInfoVo.setMergeType(examInfo.getMergeType());
                examInfoVos.add(examInfoVo);
            }

            return examInfoVos;
        } else {
            Map<String, Object> parms = new HashMap<>();
            parms.put("relationId", examId);
            List<ExamInfoVo> examInfoVos = examInfoMapper.selectEnterpriseExamInfoByParms(parms);
            for (ExamInfoVo examInfoVo : examInfoVos) {
                List<ExamSubjectVo> examSubjectVos = iExamSubjectInfoService.selectExamSubjectInfoByExamId(examInfoVo.getId());
                BigDecimal fullScore = new BigDecimal(0);
                for (ExamSubjectVo examSubjectVo : examSubjectVos) {
                    fullScore = fullScore.add(examSubjectVo.getPaperFullMarks());
                }
                examInfoVo.setPaperFullMarks(fullScore);
                examInfoVo.setExamForm(examInfo.getExamForm());
                examInfoVo.setMergeType(examInfo.getMergeType());
            }
            return examInfoVos;
        }
    }

    /**
     * 修改考试信息
     *
     * @param examInfo 修改考试信息
     * @return 结果
     */
    @Override
    public int updateExamInfo(ExamInfo examInfo) {
        examInfo.updateInfo(SecurityUtils.getUsername());
        return examInfoMapper.updateExamInfo(examInfo);
    }

    @Override
    public List<ExamFormVo> getExamForms() {
        List<ExamFormVo> result = new ArrayList<>();
        Map<Integer, String> dataMap = ExamFormEnums.map;
        Iterator<Map.Entry<Integer, String>> iterator = dataMap.entrySet().iterator();
        while (iterator.hasNext()) {
            ExamFormVo examFormVo = new ExamFormVo();
            Map.Entry<Integer, String> next = iterator.next();
            Integer key = next.getKey();
            String value = next.getValue();
            examFormVo.setLabel(value);
            examFormVo.setValue(String.valueOf(key));
            result.add(examFormVo);
        }
        return result;
    }

    @Override
    public List<EnterpriseExamVo> pageEnterpriseExamInfoSelectedList(String examId) {
        List<EnterpriseExamVo> result = new ArrayList<>();

        Map<String, Object> queryMap = new HashedMap<>();
        queryMap.put("relationId", examId);
        List<ExamInfoVo> examInfos = examInfoMapper.selectEnterpriseExamInfoByParms(queryMap);

        if (CollectionUtil.isNotEmpty(examInfos)) {
            String[] ids = examInfos.stream().map(item -> item.getId()).toArray(String[]::new);
            List<ExamSubjectVo> subjectList = examSubjectInfoMapper.selectExamSubjectInfoByExamIds(ids);
            Map<String, List<ExamSubjectVo>> subjectMap = subjectList.stream().collect(Collectors.groupingBy(ExamSubjectVo::getExamInfoId));
            List<Classification> classificationTree = classificationService.getClassificationList();
            // 封装数据，包括子考试
            for (ExamInfoVo examInfo : examInfos) {
                EnterpriseExamVo enterpriseExamVoResult = buildExamInfoData(examInfo, subjectMap, classificationTree);
                if (CollectionUtils.isNotEmpty(examInfo.getChildren())) {
                    List<EnterpriseExamVo> childrenResult = new ArrayList<>();
                    List<ExamInfoVo> children = examInfo.getChildren();
                    for (ExamInfoVo examInfoSub : children) {
                        EnterpriseExamVo enterpriseExamVoChildResult = buildExamInfoData(examInfoSub, subjectMap, classificationTree);
                        childrenResult.add(enterpriseExamVoChildResult);
                    }
                    enterpriseExamVoResult.setExamChildren(childrenResult);
                }
                result.add(enterpriseExamVoResult);
            }

        }
        return result;

    }

    @Override
    public MergeExamDetailVo mergeExamDetail(String examId) {
        MergeExamDetailVo result = new MergeExamDetailVo();
        List<EnterpriseExamVo> enterpriseExamVos = pageEnterpriseExamInfoSelectedList(examId);
        ExamInfoVo examInfo = examInfoMapper.selectExamInfoByExamId(examId);
        if (examInfo != null) {
            result.setExamId(examInfo.getId());
            result.setBeginTime(DateUtil.formatDateTime(examInfo.getExamStartDay()));
            result.setEndTime(DateUtil.formatDateTime(examInfo.getExamEndDay()));
            result.setExamName(examInfo.getExamNameConfigName());
            result.setExamType(examInfo.getExamType());
            result.setType(String.valueOf(examInfo.getMergeType()));
            result.setRemarks(examInfo.getRemarks());
            result.setExamVoList(enterpriseExamVos);

            // 如果是合并科目，返回科目
            if (CommonEnums.EXAM_MERGE_TYPE_1.getCode().equals(String.valueOf(examInfo.getMergeType()))) {
                List<ExamSubjectVo> examSubjectVos = examSubjectInfoMapper.selectExamSubjectInfoByExamId(examInfo.getId());
                for (ExamSubjectVo examSubjectVo : examSubjectVos) {
                    if (StrUtil.isNotEmpty(examSubjectVo.getSubjectId())) {
                        Map<String, Object> params = new HashedMap<>();
                        params.put("relationId", examSubjectVo.getSubjectId());
                        List<ExamSubjectInfo> subjectInfoList = examSubjectInfoMapper.selectExamSubjectInfoListAllByParms(params);
                        examSubjectVo.setRelationSubjectIdList(subjectInfoList.stream().map(item -> item.getId()).collect(Collectors.toList()));
                    }
                }
                result.setExamSubjectVoList(examSubjectVos);
            }
        }
        return result;
    }

    @Override
    public void relationRemove(String id) {
        ExamInfo examInfo = examInfoMapper.selectExamInfoById(id);
        String relationId = examInfo.getRelationId();
        Map<String, Object> parms = new HashMap<>();
        parms.put("relationId", relationId);
        List<ExamInfoVo> examInfoVos = examInfoMapper.selectEnterpriseExamInfoByParms(parms);
        if (examInfoVos.size() <= 2) {
            throw new CustomException("至少需要保留两个子考试，不允许删除!");
        }

        // 总成绩归档则不允许解除考试
        List<String> ids = examInfoVos.stream().map(item -> item.getId()).collect(Collectors.toList());
        List<EnterpriseExamineeInfo> enterpriseExamineeInfos = enterpriseExamineeInfoMapper.selectEnterpriseExamineeInfoByExamIds(ids);
        Map<String, List<EnterpriseExamineeInfo>> collectGroup = enterpriseExamineeInfos.stream()
                .filter(item -> CommonEnums.ARCHIVED_STATUS_Y.getCode().equals(item.getArchivedGroupStatus())).collect(Collectors.groupingBy(item -> item.getExamId()));
        for (ExamInfoVo examInfoVo : examInfoVos) {
            if (collectGroup.get(examInfoVo.getId()) != null) {
                throw new CustomException("考试组存在总成绩归档数据，不允许删除!");
            }
        }

        List<ExamInfoVo> examInfoVoList = new ArrayList<>();
        ExamInfoVo examInfoVo = new ExamInfoVo();
        examInfoVo.setId(id);
        examInfoVoList.add(examInfoVo);
        examInfoMapper.emptyBatchExamInfoRel(examInfoVoList);
    }

    @Cacheable(value = RedisKeyConstant.SELECT_EXAM_INFO_BY_EXAM_ID, key = "#examId")
    @Override
    public ExamInfoVo selectExamInfoByExamId(String examId) {
        return examInfoMapper.selectExamInfoByExamId(examId);
    }

    @Override
    public List<ExamCertificateVo> getCertificateList(String examId) {
        // 是否绑定了证书
        return zsInfoService.lambdaQuery()
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .eq(ZsInfo::getExamId, examId)
                .eq(ZsInfo::getCertificatePublishType, CertificatePublishTypeEnums.RELATION_CJ_PUBLISH.getCode())
                .list()
                .stream()
                .map(data -> ExamCertificateVo.builder()
                        .zsInfoId(data.getId())
                        .certificateName(data.getCertificateName())
                        .build())
                .collect(Collectors.toList());
    }

    @Override
    public List<ExamInfo> listByTaskId(String timeId) {
        return examInfoMapper.listByTaskId(timeId);
    }

    @Override
    public void deleteExamInfo(String examInfoId) {
        examInfoMapper.deleteCandidateConfig(examInfoId);
        examInfoMapper.deleteCandidateInfo(examInfoId);
        examInfoMapper.deleteChangedExamInfo(examInfoId);
        examInfoMapper.deleteEnterpriseExamScoreLineSetting(examInfoId);
        examInfoMapper.deleteEnterpriseExamScoreLineSettingSub(examInfoId);
        examInfoMapper.deleteEnterpriseExamineeAnalysisData(examInfoId);
        examInfoMapper.deleteEnterpriseExamineeCertificateRelation(examInfoId);
        examInfoMapper.deleteEnterpriseExamineeInfo(examInfoId);
        examInfoMapper.deleteEnterpriseExamineeSubjectGrade(examInfoId);
        examInfoMapper.deleteExamNameConfig(examInfoId);
        examInfoMapper.deleteExamPostInfo(examInfoId);
        examInfoMapper.deleteExamPostScoreLineSetting(examInfoId);
        examInfoMapper.deleteExamPublishCertificateInfo(examInfoId);
        examInfoMapper.deleteExamPublishSubjectInfo(examInfoId);
        examInfoMapper.deleteExamPublishInfo(examInfoId);
        examInfoMapper.deleteExamResultDatadlRecord(examInfoId);
        examInfoMapper.deleteExamReviewInfo(examInfoId);
        examInfoMapper.deleteExamScoreAnalysisLine(examInfoId);
        examInfoMapper.deleteExamStemInfo(examInfoId);
        examInfoMapper.deleteExamSubjectNameConfig(examInfoId);
        examInfoMapper.deleteExamSubjectInfo(examInfoId);
        examInfoMapper.deleteExamineeExamInfo(examInfoId);
        examInfoMapper.deleteExamineeExamPaperInfo(examInfoId);
        examInfoMapper.deleteExamineeGradeInfo(examInfoId);
        examInfoMapper.deleteExamineeSubjectGradeInfo(examInfoId);
        examInfoMapper.deleteExamInfo(examInfoId);
    }

    @Override
    public ExamInfo examDetail(String id) {
        return examInfoMapper.selectExamInfoById(id);
    }

}
